package com.zdkj.edge.door.demo;

import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.spicdt.iedge.psdk.EdgeDataService;
import com.spicdt.iedge.psdk.EdgeService;
import com.spicdt.iedge.psdk.ProtocolService;
import com.spicdt.iedge.psdk.annotation.EnableSpringWebContext;
import com.spicdt.iedge.psdk.data.CommandSubscription;
import com.spicdt.iedge.psdk.data.DeviceAlarm;
import com.spicdt.iedge.psdk.device.DeviceInfo;
import com.spicdt.iedge.psdk.meta.Configuration;
import com.spicdt.iedge.psdk.meta.ConfigureType;
import com.spicdt.iedge.psdk.meta.StateEnum;
import com.zdkj.edge.door.demo.conf.AdmsConf;
import com.zdkj.edge.door.demo.model.api.*;
import com.zdkj.edge.door.demo.handler.AdmsCommandHandler;
import com.zdkj.edge.vehicle.demo.model.api.*;
import com.zdkj.edge.door.demo.service.AdmsApiService;
import com.zdkj.edge.door.demo.service.impl.AdmsApiServiceImpl;
import com.zdkj.edge.door.demo.utils.TimeUtil;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

/**
 * ADMS 协议服务实现类，用于管理设备状态、事件拉取、RPC订阅等。
 * 用于连接第三方人脸识别系统。
 */
@Slf4j
@EnableSpringWebContext
public class AdmsProtocolService implements ProtocolService {

    /** ADMS 配置对象 */
    private AdmsConf admsConf;

    /** 边平台服务接口 */
    private final EdgeService edgeService;

    /** 边平台数据服务能力 */
    @Getter
    private EdgeDataService edgeDataService;

    /** 通信协议配置 */
    private Configuration configuration;

    /** 当前服务状态 */
    private StateEnum stateEnum = StateEnum.online;

    /** RPC 指令处理器 */
    private AdmsCommandHandler rpcProcessor;

    /** ADMS API 接口服务 */
    private AdmsApiService admsApiService;

    /** 第三方设备与边平台设备映射关系 */
    public static final Map<String, DeviceInfo> deviceInfoMapping = new ConcurrentHashMap<>();

    /** 线程池：用于状态检查和事件轮询 */
    private final ScheduledExecutorService scheduledExecutor = Executors.newScheduledThreadPool(2);

    private final AccessRecordStateManager stateManager = new AccessRecordStateManager();


    public AdmsProtocolService(EdgeService edgeService) {
        this.edgeService = edgeService;
    }

    @Override
    public Configuration getConfiguration() {
        return configuration;
    }

    /**
     * 初始化协议服务
     * @param configuration 配置对象
     */
    @Override
    public void init(Configuration configuration) throws Exception {
        try {
            this.configuration = configuration;
            this.edgeDataService = edgeService.getEdgeCapability(EdgeDataService.class);

            log.info("[ADMS] 初始化人脸道闸协议服务，channelId: {}", configuration.getChannelId());
            this.admsConf = loadConfiguration(configuration);

            initDeviceMapping(configuration.getChannelId());
            this.admsApiService = new AdmsApiServiceImpl(admsConf);
            subscribeDeviceCommands(configuration.getChannelId());

            scheduledExecutor.scheduleAtFixedRate(this::checkDeviceStatus, 0, 400, TimeUnit.SECONDS);
            scheduledExecutor.scheduleAtFixedRate(this::fetchAccessEvents, 10, 10, TimeUnit.SECONDS);

        } catch (Exception e) {
            log.error("[ADMS] 初始化异常，channelId: {}，错误: {}", configuration.getChannelId(), e.getMessage(), e);
        }
    }

    /**
     * 更新协议配置
     */
    @Override
    public void update(Configuration configuration) throws Exception {
        try {
            destroy();
            init(configuration);
        } catch (Exception e) {
            log.error("[ADMS] 配置更新失败，channelId: {}", configuration.getChannelId(), e);
            throw e;
        }
    }

    /**
     * 销毁服务
     */
    @Override
    public void destroy() throws Exception {
        scheduledExecutor.shutdownNow();
        stateEnum = StateEnum.offline;
        rpcProcessor = null;
        admsApiService = null;
    }

    /**
     * 初始化设备映射
     */
    private void initDeviceMapping(String channelId) {
        List<DeviceInfo> deviceList = edgeService.deviceList(channelId);
        if (CollectionUtils.isEmpty(deviceList)) {
            log.warn("[ADMS] 无设备信息，channelId: {}", channelId);
            return;
        }
        deviceList.forEach(deviceInfo ->
            deviceInfoMapping.put(deviceInfo.getDeviceKey(), deviceInfo)
        );
    }

    /**
     * 解析配置
     */
    private AdmsConf loadConfiguration(Configuration configuration) throws Exception {
        try {
            ObjectMapper mapper = new ObjectMapper();
            AdmsConf config = ConfigureType.JSON.equals(configuration.getConfigureType())
                ? mapper.treeToValue(mapper.readTree(configuration.getConfiguration()), AdmsConf.class)
                : mapper.readValue(getClass().getClassLoader().getResourceAsStream(configuration.getConfiguration()), AdmsConf.class);

            log.info("[ADMS] 协议配置加载完成，channelId: {}", configuration.getChannelId());
            return config;
        } catch (Exception e) {
            log.error("[ADMS] 配置解析失败，channelId: {}", configuration.getChannelId(), e);
            edgeService.channelError(configuration.getChannelId(), e);
            throw e;
        }
    }

    @Override
    public StateEnum getState() {
        return stateEnum;
    }

    @Override
    public CompletableFuture<Boolean> setState(StateEnum stateEnum) {
        this.stateEnum = stateEnum;
        return CompletableFuture.completedFuture(true);
    }

    @Override
    public void restart() {
        try {
            update(configuration);
        } catch (Exception e) {
            log.error("[ADMS] 重启失败，channelId: {}", configuration.getChannelId(), e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 订阅设备 RPC 指令
     */
    private void subscribeDeviceCommands(String channelId) {
        log.info("[ADMS] 开始订阅设备 RPC 指令，channelId: {}", channelId);
        this.rpcProcessor = new AdmsCommandHandler(admsApiService, edgeService, admsConf);

        List<DeviceInfo> deviceList = edgeService.deviceList(channelId);
        if (CollectionUtils.isEmpty(deviceList)) {
            log.warn("[ADMS] 无设备可订阅，channelId: {}", channelId);
            return;
        }

        deviceList.forEach(deviceInfo -> {
            try {
                edgeService.subscribe(new CommandSubscription(channelId, deviceInfo.getDeviceKey(), rpcProcessor));
            } catch (Exception e) {
                log.error("[ADMS] 设备订阅失败，deviceKey: {}，channelId: {}，原因: {}", deviceInfo.getDeviceKey(), channelId, e.getMessage(), e);
            }
        });
    }

    /**
     * 检查设备在线状态并上报
     */
    private void checkDeviceStatus() {
        if (!StateEnum.online.equals(stateEnum)) return;

        log.info("[ADMS] 开始检测设备在线状态，channelId: {}", configuration.getChannelId());
        List<DeviceInfo> deviceList = edgeService.deviceList(configuration.getChannelId());

        if (CollectionUtils.isEmpty(deviceList)) return;

        deviceList.forEach(deviceInfo -> {
            String srcDeviceCode = deviceInfo.getSouthDeviceCode();
            if (StrUtil.isBlank(srcDeviceCode)) {
                srcDeviceCode = deviceInfo.getMappingProperty("srcDeviceCode");
                if (StrUtil.isBlank(srcDeviceCode)) {
                    srcDeviceCode = deviceInfo.getMappingProperty("srcDeviceName");
                }
            }

            boolean online = checkDeviceOnline(srcDeviceCode);
            if (online) {
                edgeService.deviceOnline(deviceInfo.getDeviceKey());
            } else {
                edgeService.deviceOffline(deviceInfo.getDeviceKey());
            }
        });
    }

    /**
     * 调用 API 判断设备是否在线
     */
    private boolean checkDeviceOnline(String srcDeviceCode) {
        try {
            ApiDeviceListRequest request = new ApiDeviceListRequest();
            request.setDeviceId(Integer.valueOf(srcDeviceCode));
            ApiResponse<List<ApiDeviceListResponse>> response = admsApiService.getDeviceList(request);

            if (response.getTag() == 1 && !CollectionUtils.isEmpty(response.getData())) {
                return Boolean.TRUE.equals(response.getData().get(0).getIsLine());
            }
        } catch (Exception e) {
            log.error("[ADMS] 检查设备是否在线失败，srcDeviceCode: {}，错误: {}", srcDeviceCode, e.getMessage());
        }
        return false;
    }

    /**
     * 拉取门禁事件记录并推送到边平台。
     * 根据每台设备的 deviceKey，筛选出对应的门禁记录，
     * 并记录最后一次事件时间，避免重复推送。
     */
    /**
     * 轮询 ADMS 门禁系统的通行记录，并转化为告警事件推送至边平台
     */
    private void fetchAccessEvents() {
        String channelId = configuration.getChannelId();
        log.info("[ADMS] 开始轮询门禁通行记录，channelId: {}", channelId);

        List<DeviceInfo> deviceList = edgeService.deviceList(channelId);
        if (CollectionUtils.isEmpty(deviceList)) {
            log.warn("[ADMS] 通信通道[{}]下未发现设备，跳过事件轮询。", channelId);
            return;
        }

        try {
            // 构造请求参数：统一获取 10 分钟内的所有通行记录
            ApiAccessRecordRequest request = new ApiAccessRecordRequest();
            request.setPageIndex(1);
            request.setPageSize(500);
            request.setLocationId("");  // 若为空则默认查所有地点
            request.setStartTime(TimeUtil.getTimeMinutesAgo(10));
            request.setEndTime(TimeUtil.getNow());

            ApiResponse<List<ApiAccessRecordResponse>> response = admsApiService.getAccessRecordList(request);
            if (response.getTag() != 1 || CollectionUtils.isEmpty(response.getData())) {
                log.info("[ADMS] 本轮未获取到门禁通行记录，channelId: {}", channelId);
                return;
            }

            // 构建设备ID到设备映射
            Map<String, DeviceInfo> southDeviceCodeMap = deviceList.stream()
                .filter(d -> StrUtil.isNotBlank(d.getSouthDeviceCode()))
                .collect(Collectors.toMap(DeviceInfo::getSouthDeviceCode, d -> d));

            for (ApiAccessRecordResponse record : response.getData()) {
                String tdDeviceCode = String.valueOf(record.getTdDeviceId());
                DeviceInfo device = southDeviceCodeMap.get(tdDeviceCode);
                if (device == null) {
                    log.debug("[ADMS] 忽略未知设备的记录，tdDeviceId: {}", tdDeviceCode);
                    continue;
                }

                String deviceKey = device.getDeviceKey();
                String lastPushTime = stateManager.getLastBrushTime(deviceKey);

                if (StrUtil.isNotBlank(lastPushTime) && record.getBrushTime().compareTo(lastPushTime) <= 0) {
                    log.debug("[ADMS] 跳过重复事件，deviceKey: {}，recordTime: {} <= lastPushTime: {}",
                        deviceKey, record.getBrushTime(), lastPushTime);
                    continue;
                }

                // 推送为设备告警事件
                DeviceAlarm alarm = record.toAlarm(deviceKey);
                edgeService.deviceAlarmUpdate(deviceKey, Collections.singletonList(alarm));

                // 更新最后推送时间
                try {
                    stateManager.updateLastBrushTime(deviceKey, record.getBrushTime());
                } catch (Exception ex) {
                    log.warn("[ADMS] 更新设备[{}]的最后事件时间失败，time: {}，原因：{}", deviceKey, record.getBrushTime(), ex.getMessage());
                }

                log.info("[ADMS] 推送通行事件成功，channelId: {}，deviceKey: {}，eventId: {}",
                    channelId, deviceKey, record.getId());
            }

        } catch (Exception e) {
            log.error("[ADMS] 通行记录轮询失败，channelId: {}，异常: {}", channelId, e.getMessage(), e);
        }
    }


}


